home *** CD-ROM | disk | FTP | other *** search
- /* integration/qmomof.c
- *
- * Copyright (C) 1996, 1997, 1998, 1999, 2000 Brian Gough
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- #include <config.h>
- #include <stdlib.h>
- #include <gsl/gsl_integration.h>
- #include <gsl/gsl_errno.h>
-
- static void
- compute_moments (double par, double * cheb);
-
- static int
- dgtsl (size_t n, double *c, double *d, double *e, double *b);
-
- gsl_integration_qawo_table *
- gsl_integration_qawo_table_alloc (double omega, double L,
- enum gsl_integration_qawo_enum sine,
- size_t n)
- {
- gsl_integration_qawo_table *t;
- double * chebmo;
-
- if (n == 0)
- {
- GSL_ERROR_VAL ("table length n must be positive integer",
- GSL_EDOM, 0);
- }
-
- t = (gsl_integration_qawo_table *)
- malloc (sizeof (gsl_integration_qawo_table));
-
- if (t == 0)
- {
- GSL_ERROR_VAL ("failed to allocate space for qawo_table struct",
- GSL_ENOMEM, 0);
- }
-
- chebmo = (double *) malloc (25 * n * sizeof (double));
-
- if (chebmo == 0)
- {
- free (t);
- GSL_ERROR_VAL ("failed to allocate space for chebmo block",
- GSL_ENOMEM, 0);
- }
-
- t->n = n;
- t->sine = sine;
- t->omega = omega;
- t->L = L;
- t->par = 0.5 * omega * L;
- t->chebmo = chebmo;
-
- /* precompute the moments */
-
- {
- size_t i;
- double scale = 1.0;
-
- for (i = 0 ; i < t->n; i++)
- {
- compute_moments (t->par * scale, t->chebmo + 25*i);
- scale *= 0.5;
- }
- }
-
- return t;
- }
-
- int
- gsl_integration_qawo_table_set (gsl_integration_qawo_table * t,
- double omega, double L,
- enum gsl_integration_qawo_enum sine)
- {
- t->omega = omega;
- t->sine = sine;
- t->L = L;
- t->par = 0.5 * omega * L;
-
- /* recompute the moments */
-
- {
- size_t i;
- double scale = 1.0;
-
- for (i = 0 ; i < t->n; i++)
- {
- compute_moments (t->par * scale, t->chebmo + 25*i);
- scale *= 0.5;
- }
- }
-
- return GSL_SUCCESS;
- }
-
-
- int
- gsl_integration_qawo_table_set_length (gsl_integration_qawo_table * t,
- double L)
- {
- /* return immediately if the length is the same as the old length */
-
- if (L == t->L)
- return GSL_SUCCESS;
-
- /* otherwise reset the table and compute the new parameters */
-
- t->L = L;
- t->par = 0.5 * t->omega * L;
-
- /* recompute the moments */
-
- {
- size_t i;
- double scale = 1.0;
-
- for (i = 0 ; i < t->n; i++)
- {
- compute_moments (t->par * scale, t->chebmo + 25*i);
- scale *= 0.5;
- }
- }
-
- return GSL_SUCCESS;
- }
-
-
- void
- gsl_integration_qawo_table_free (gsl_integration_qawo_table * t)
- {
- free (t->chebmo);
- free (t);
- }
-
- static void
- compute_moments (double par, double *chebmo)
- {
- double v[28], d[25], d1[25], d2[25];
-
- const size_t noeq = 25;
-
- const double par2 = par * par;
- const double par4 = par2 * par2;
- const double par22 = par2 + 2.0;
-
- const double sinpar = sin (par);
- const double cospar = cos (par);
-
- size_t i;
-
- /* compute the chebyschev moments with respect to cosine */
-
- double ac = 8 * cospar;
- double as = 24 * par * sinpar;
-
- v[0] = 2 * sinpar / par;
- v[1] = (8 * cospar + (2 * par2 - 8) * sinpar / par) / par2;
- v[2] = (32 * (par2 - 12) * cospar
- + (2 * ((par2 - 80) * par2 + 192) * sinpar) / par) / par4;
-
- if (fabs (par) <= 24)
- {
- /* compute the moments as the solution of a boundary value
- problem using the asyptotic expansion as an endpoint */
-
- double an2, ass, asap;
- double an = 6;
- size_t k;
-
- for (k = 0; k < noeq - 1; k++)
- {
- an2 = an * an;
- d[k] = -2 * (an2 - 4) * (par22 - 2 * an2);
- d2[k] = (an - 1) * (an - 2) * par2;
- d1[k + 1] = (an + 3) * (an + 4) * par2;
- v[k + 3] = as - (an2 - 4) * ac;
- an = an + 2.0;
- }
-
- an2 = an * an;
-
- d[noeq - 1] = -2 * (an2 - 4) * (par22 - 2 * an2);
- v[noeq + 2] = as - (an2 - 4) * ac;
- v[3] = v[3] - 56 * par2 * v[2];
-
- ass = par * sinpar;
- asap = (((((210 * par2 - 1) * cospar - (105 * par2 - 63) * ass) / an2
- - (1 - 15 * par2) * cospar + 15 * ass) / an2
- - cospar + 3 * ass) / an2
- - cospar) / an2;
- v[noeq + 2] = v[noeq + 2] - 2 * asap * par2 * (an - 1) * (an - 2);
-
- dgtsl (noeq, d1, d, d2, v + 3);
-
- }
- else
- {
- /* compute the moments by forward recursion */
- size_t k;
- double an = 4;
-
- for (k = 3; k < 13; k++)
- {
- double an2 = an * an;
- v[k] = ((an2 - 4) * (2 * (par22 - 2 * an2) * v[k - 1] - ac)
- + as - par2 * (an + 1) * (an + 2) * v[k - 2])
- / (par2 * (an - 1) * (an - 2));
- an = an + 2.0;
- }
- }
-
-
- for (i = 0; i < 13; i++)
- {
- chebmo[2 * i] = v[i];
- }
-
- /* compute the chebyschev moments with respect to sine */
-
- v[0] = 2 * (sinpar - par * cospar) / par2;
- v[1] = (18 - 48 / par2) * sinpar / par2 + (-2 + 48 / par2) * cospar / par;
-
- ac = -24 * par * cospar;
- as = -8 * sinpar;
-
- if (fabs (par) <= 24)
- {
- /* compute the moments as the solution of a boundary value
- problem using the asyptotic expansion as an endpoint */
-
- size_t k;
- double an2, ass, asap;
- double an = 5;
-
- for (k = 0; k < noeq - 1; k++)
- {
- an2 = an * an;
- d[k] = -2 * (an2 - 4) * (par22 - 2 * an2);
- d2[k] = (an - 1) * (an - 2) * par2;
- d1[k + 1] = (an + 3) * (an + 4) * par2;
- v[k + 2] = ac + (an2 - 4) * as;
- an = an + 2.0;
- }
-
- an2 = an * an;
-
- d[noeq - 1] = -2 * (an2 - 4) * (par22 - 2 * an2);
- v[noeq + 1] = ac + (an2 - 4) * as;
- v[2] = v[2] - 42 * par2 * v[1];
-
- ass = par * cospar;
- asap = (((((105 * par2 - 63) * ass - (210 * par2 - 1) * sinpar) / an2
- + (15 * par2 - 1) * sinpar
- - 15 * ass) / an2 - sinpar - 3 * ass) / an2 - sinpar) / an2;
- v[noeq + 1] = v[noeq + 1] - 2 * asap * par2 * (an - 1) * (an - 2);
-
- dgtsl (noeq, d1, d, d2, v + 2);
-
- }
- else
- {
- /* compute the moments by forward recursion */
- size_t k;
- double an = 3;
- for (k = 2; k < 12; k++)
- {
- double an2 = an * an;
- v[k] = ((an2 - 4) * (2 * (par22 - 2 * an2) * v[k - 1] + as)
- + ac - par2 * (an + 1) * (an + 2) * v[k - 2])
- / (par2 * (an - 1) * (an - 2));
- an = an + 2.0;
- }
- }
-
- for (i = 0; i < 12; i++)
- {
- chebmo[2 * i + 1] = v[i];
- }
-
- }
-
- static int
- dgtsl (size_t n, double *c, double *d, double *e, double *b)
- {
- /* solves a tridiagonal matrix A x = b
-
- c[1 .. n - 1] subdiagonal of the matrix A
- d[0 .. n - 1] diagonal of the matrix A
- e[0 .. n - 2] superdiagonal of the matrix A
-
- b[0 .. n - 1] right hand side, replaced by the solution vector x */
-
- size_t k;
-
- c[0] = d[0];
-
- if (n == 0)
- {
- return GSL_SUCCESS;
- }
-
- if (n == 1)
- {
- b[0] = b[0] / d[0] ;
- return GSL_SUCCESS;
- }
-
- d[0] = e[0];
- e[0] = 0;
- e[n - 1] = 0;
-
- for (k = 0; k < n - 1; k++)
- {
- size_t k1 = k + 1;
-
- if (fabs (c[k1]) >= fabs (c[k]))
- {
- {
- double t = c[k1];
- c[k1] = c[k];
- c[k] = t;
- };
- {
- double t = d[k1];
- d[k1] = d[k];
- d[k] = t;
- };
- {
- double t = e[k1];
- e[k1] = e[k];
- e[k] = t;
- };
- {
- double t = b[k1];
- b[k1] = b[k];
- b[k] = t;
- };
- }
-
- if (c[k] == 0)
- {
- return GSL_FAILURE ;
- }
-
- {
- double t = -c[k1] / c[k];
-
- c[k1] = d[k1] + t * d[k];
- d[k1] = e[k1] + t * e[k];
- e[k1] = 0;
- b[k1] = b[k1] + t * b[k];
- }
-
- }
-
- if (c[n - 1] == 0)
- {
- return GSL_FAILURE;
- }
-
-
- b[n - 1] = b[n - 1] / c[n - 1];
-
- b[n - 2] = (b[n - 2] - d[n - 2] * b[n - 1]) / c[n - 2];
-
- for (k = n ; k > 2; k--)
- {
- size_t kb = k - 3;
- b[kb] = (b[kb] - d[kb] * b[kb + 1] - e[kb] * b[kb + 2]) / c[kb];
- }
-
- return GSL_SUCCESS;
- }
-